# coding=utf-8
"""
author = jamon
"""

import threading

from asyncio.coroutines import iscoroutine
from obespoir.share.espoir_log import global_log


# class RpcMsgType(object):
#     """Rpc接口收到的消息类型"""
#
#     LOCAL = 1   # 需要本地处理的消息
#     TRANS = 2   # 需要转发的消息
#     WEB_SOCKET = 3  # 需要直接推送给websocket客户端的消息


class ObRoute(object):
    """消息分发"""

    def __init__(self):
        self._lock = threading.RLock()
        self._targets = {}  # Keeps track of targets internally

    def __iter__(self):
        return self._targets.values()

    def map_target(self, target):
        """Add a target to the service."""
        self._lock.acquire()
        try:
            key = int(target.__name__.split('_')[-1])
            if key in self._targets.keys():
                exist_target = self._targets.get(key)
                raise "target [%d] Already exists,\
                Conflict between the %s and %s" % (
                    key, exist_target.__name__, target.__name__)
            self._targets[key] = target
        finally:
            self._lock.release()

    def unmap_target(self, target):
        """Remove a target from the service."""
        self._lock.acquire()
        try:
            key = int(target.__name__.split('_')[-1])
            if key in self._targets:
                del self._targets[key]
        finally:
            self._lock.release()

    def unmap_target_by_key(self, target_key):
        """Remove a target from the service."""
        self._lock.acquire()
        try:
            del self._targets[target_key]
        finally:
            self._lock.release()

    def get_target(self, target_key):
        """Get a target from the service by name."""
        self._lock.acquire()
        try:
            target = self._targets.get(target_key, None)
        finally:
            self._lock.release()
        return target

    async def call_target(self, target_key, *args, **kw):
        """
        call Target        
        @param target_key:  ID
        """
        target = self.get_target(target_key)
        self._lock.acquire()
        try:
            if not target:
                global_log.warn("key not found", key=target_key)
                return None

            result = target(target_key, *args, **kw)

            if iscoroutine(result):
                result = await result
            global_log.debug("end", key=target_key, result=result)
            return result
        finally:
            self._lock.release()
